package com.ruoyi.common.utils.file;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruoyi.common.config.AiBaseInfoConfig;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;

import static org.springframework.http.HttpMethod.POST;

@Component
@Slf4j
public class TextinOcr {

    /**
     * 定义textin API的基础URL，用于后续的网络请求
     */
    private static final String TEXT_API_URL = AiBaseInfoConfig.getTextInUrl();

    /**
     * 定义应用的ID，用于身份验证
     */
    private static final String TEXT_IN_APP_ID = AiBaseInfoConfig.getTextInApiId();
    /**
     * 定义应用的密钥，用于身份验证
     */
    private static final String TEXT_IN_APP_SECRET = AiBaseInfoConfig.getTextInApiKey();

    /**
     * 构建URL
     * <p>
     * 此方法根据提供的参数构建一个URL，用于向Textin API发送请求
     * <p>
     * /**
     * 将PDF文件转换为Markdown格式的响应
     *
     * @param pdfFile PDF文件的字节数组
     * @param params  PDF转换的参数配置
     * @return PdfToMarkdownResponse对象，包含转换后的Markdown数据
     */
    public static PdfToMarkdownResponse convertPdfToMarkdown(byte[] pdfFile, PdfToMarkdownParams params) {
        // 使用restTemplate
        RestTemplate restTemplate = new RestTemplate();

        // 构造请求头
        HttpHeaders headers = new HttpHeaders();
        headers.set("x-ti-app-id", TEXT_IN_APP_ID);
        headers.set("x-ti-secret-code", TEXT_IN_APP_SECRET);
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);

        // 构造url
        String url = buildUrl(params);
        log.info(url);

        // 发送请求
        HttpEntity<byte[]> requestEntity = new HttpEntity<>(pdfFile, headers);
        ResponseEntity<PdfToMarkdownResponse> response = restTemplate.exchange(
                url,
                POST,
                requestEntity,
                PdfToMarkdownResponse.class);
        log.info(response.getBody().toString());

        return response.getBody();
    }

    /**
     * 将PDF文件转换为Markdown格式的字符串
     * <p>
     * 此方法接收一个MultipartFile对象作为输入，尝试将其内容转换为Markdown格式的文本
     * 它使用了PdfToMarkdownParams类来设置转换参数，如表格风味、解析模式等
     *
     * @param file 要转换的PDF文件，作为MultipartFile对象
     * @return 转换后的Markdown格式字符串，如果发生错误则返回错误信息
     * @throws IOException 如果在读取文件过程中发生I/O错误
     */
    public static String getPdfToMdResult(MultipartFile file) {

        // 初始化PDF转换参数
        PdfToMarkdownParams params = new PdfToMarkdownParams();
        params.setTableFlavor("table");
        params.setParseMode("auto");
        params.setMarkdownDetails("0");
        params.setApplyDocumentTree(false);
        params.setPage_details("0");
        // params.setGetImage("both");
        // params.setPageStart(0);
        // params.setPageCount(10);

        try {
            // 读取PDF文件的字节内容
            byte[] pdfBytes = file.getBytes();
            // 调用转换方法，获得转换响应
            PdfToMarkdownResponse response = convertPdfToMarkdown(pdfBytes, params);
            // 打印响应信息
            System.out.println("Response Code: " + response.getCode());
            System.out.println("Response Message: " + response.getMessage());
            // 输出转换后的Markdown内容
            System.out.println("Markdown: " + response.getResult().getMarkdown());
            // 返回转换后的Markdown字符串
            return response.getResult().getMarkdown();
        } catch (IOException e) {
            // 如果发生I/O错误，打印错误信息并返回错误消息
            log.error(e.getMessage(), e);
            return e.getMessage();
        }
    }

    /**
     * 将PDF文件转换为Markdown格式的字符串
     * 此方法读取指定路径的PDF文件，并使用PdfToMarkdownParams类的参数将其转换为Markdown格式的字符串
     *
     * @param filePath PDF文件的路径
     * @return 转换后的Markdown格式字符串
     * @throws IOException 如果在读取文件过程中发生I/O错误
     */
    public static String getPdfToMdResult(String filePath) throws IOException {
        String textInApiId = AiBaseInfoConfig.getTextInApiId();
        // 创建File对象以访问PDF文件
        File pdfFile = new File(filePath);
        // 初始化PdfToMarkdownParams对象，并设置转换参数
        PdfToMarkdownParams params = new PdfToMarkdownParams();
        params.setTableFlavor("md");
        params.setParseMode("auto");
        params.setMarkdownDetails("0");
        params.setApplyDocumentTree(false);
        params.setPage_details("0");
        // params.setGetImage("both");
        // params.setPageStart(0);
        // params.setPageCount(10);

        try {
            // 读取PDF文件的所有字节
            byte[] pdfBytes = Files.readAllBytes(pdfFile.toPath());

            // 调用convertPdfToMarkdown方法将PDF字节转换为Markdown格式的字符串
            PdfToMarkdownResponse response = convertPdfToMarkdown(pdfBytes, params);

            // 打印响应信息
            System.out.println("Response Code: " + response.getCode());
            System.out.println("Response Message: " + response.getMessage());

            // 打印并返回转换后的Markdown字符串
            System.out.println("Markdown: " + response.getResult().getMarkdown());
            return response.getResult().getMarkdown();
        } catch (IOException e) {
            // 如果发生I/O错误，打印堆栈跟踪信息并返回null
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据PdfToMarkdownParams参数构建请求URL
     * 此方法考虑到了PDF转换所需的多种参数，通过UriComponentsBuilder构建最终的请求URL
     * 每个if语句检查参数是否不为空，如果不为空，则将其作为查询参数添加到URL中
     *
     * @param params 包含多个PDF转换选项的参数对象，用于定制转换过程
     * @return 返回构建好的URL字符串，用于发起请求
     */
    private static String buildUrl(PdfToMarkdownParams params) {
        UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(TEXT_API_URL);
        if (params.getPdfPwd() != null) {
            uriBuilder.queryParam("pdf_pwd", params.getPdfPwd());
        }
        if (params.getDpi() != null) {
            uriBuilder.queryParam("dpi", params.getDpi());
        }
        if (params.getPageStart() != null) {
            uriBuilder.queryParam("page_start", params.getPageStart());
        }
        if (params.getPageCount() != null) {
            uriBuilder.queryParam("page_count", params.getPageCount());
        }
        if (params.getApplyDocumentTree() != null) {
            uriBuilder.queryParam("apply_document_tree", params.getApplyDocumentTree());
        }
        if (params.getMarkdownDetails() != null) {
            uriBuilder.queryParam("markdown_details", params.getMarkdownDetails());
        }
        if (params.getTableFlavor() != null) {
            uriBuilder.queryParam("table_flavor", params.getTableFlavor());
        }
        if (params.getGetImage() != null) {
            uriBuilder.queryParam("get_image", params.getGetImage());
        }
        if (params.getParseMode() != null) {
            uriBuilder.queryParam("parse_mode", params.getParseMode());
        }
        return uriBuilder.build().toUriString();
    }
}

@Data
class PdfToMarkdownParams {
    private String pdfPwd;
    private Integer dpi;
    private Integer pageStart;
    private Integer pageCount;
    private Boolean applyDocumentTree;
    private String markdownDetails;
    private String tableFlavor;
    private String getImage;
    private String parseMode;
    private String page_details;
}

@Data
class PdfToMarkdownResponse {
    private int code;
    private String message;
    private Result result;
    private String version;
    private long duration;
    private List<Metric> metrics;
}

@Data
class Result {
    private String markdown;
    private List<Detail> detail;
}

@Data
class Detail {
    @JsonProperty("outline_level")
    private int outlineLevel;
    @JsonProperty("image_url")
    private String imageUrl;
    private String text;
    private long pageId;
    private int content;
    @JsonProperty("paragraph_id")
    private long paragraphId;
    private String type;
    private List<Long> position;
}

@Data
class Metric {
    private String status;
    @JsonProperty("image_id")
    private String imageId;
    private double durations;
    private double pageId;
}
